package br.com.sgr.infra.persistencia;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;

import br.com.sgr.infra.mensagem.Mensagem;


/**
 * Define um objeto persistente no sistema.
 */
@MappedSuperclass
@SuppressWarnings("serial")
public abstract class ObjetoPersistente implements ObjetoValidavel, Serializable {

    protected Integer id;

    /**
     * Recupera o identificador do objeto.
     * 
     * @return Identificador do objeto.
     */
    @Transient
    public abstract Integer getId();

    /**
     * Configura o identificador do objeto.
     * 
     * @param pk Valor a ser configurado na pk.
     */
    public void setId(Integer id) {
        this.id = id;
    }
    
    public List<Mensagem> validar() {
        return validar(this);
    }
    
    private <E> List<Mensagem> validar(E obj) {
    	List<Mensagem> mensagens = new ArrayList<Mensagem>();
    	List<String> parametros = null;
    	
    	ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    	Validator validator = factory.getValidator();
    	Set<ConstraintViolation<E>> constraintViolations = validator.validate(obj);
    	for (ConstraintViolation<E> violacao : constraintViolations) {
    		String chaveMensagem = violacao.getConstraintDescriptor().getAnnotation().annotationType().getName();
    		String propriedade= violacao.getRootBeanClass().getSimpleName() 
    				+ "." + violacao.getPropertyPath().toString();
    		
    		parametros = new ArrayList<String>();
    		parametros.add(LabelConverter.getInstance().getAsString(propriedade));
    		adicionarParametrosAdicionais(parametros, violacao);
    		
			mensagens.add(new Mensagem(chaveMensagem, parametros));
		}
    	
        return mensagens;
    }

	private <E> void adicionarParametrosAdicionais(List<String> parametros,
			ConstraintViolation<E> violacao) {
		
		adicionarParametro(violacao, parametros, "value");
		adicionarParametro(violacao, parametros, "min");
		adicionarParametro(violacao, parametros, "max");
	}

	private <E> void adicionarParametro(ConstraintViolation<E> violacao, List<String> parametros,  String atributo) {
		if (violacao.getConstraintDescriptor().getAttributes().get(atributo) != null) {
			parametros.add(violacao.getConstraintDescriptor().getAttributes().get(atributo).toString());
		}
	}
    
}